SpringMVC 数组接收参数方式

遇到的问题

最近入了 springMVC 的坑,今天在写接口的时候,后端需要接收前端传递的一个字符串数组来批量删除类别,照常写出如下代码:

1
2
3
4
5
6
@RequestMapping("delete.do")
@ResponseBody
public ServerResponse deleteCategory(@RequestParam(value = "idArray[]", defaultValue="") List<String> categoryIdArray) {
logger.info(categoryIdArray.toString()); // 这里一直为空数组[]
return iProductCategoryService.deleteProductCategory(categoryIdArray);
}
1
2
3
4
5
6
let stringArray = ['17']
deleteCategoryApi({
idArray: stringArray
}).then(res => {
console.log(res)
})

发现上面logger.info打印出来的数组一直为空,前端采用 axios 来发送请求,但是不管怎么尝试就是接收不到前端传递过来的字符串,改用单纯数组接收参数或者 ArrayList 也一样的。

发现问题原因

之后通过查阅资料发现,axios 默认的 content-type 是 application/json, 这里后端需要用 formdata 的方式,后端才能获取到数据。

问题本到这里就结束了,但是我除了文件上传之类的,通常不太喜欢通过 formdata 的方式提交数据,SO,我认为应该还有别的解决方式。然后导致接下来踩了更多的坑,但是也收获了很多。

解决方案

方案一

方案一就是上面提到的,修改 axios 提交数据时候的 content-type 为 formdata,这个方案后端不需要改动,必须使用(@RequireParam(“idArray[]”) String[] idArray) 接收。

其它提交方式:

使用表单提交: 无法直接使用表单提交,需要转换成jq.ajax等方式提交

使用jq.ajax提交: 直接提交

方案二

indices 索引方式,前端通过 qs 修改 axios 的序列化方式为 indices,即:

1
example: ?a[0]=1&a[1]=2&a[2]=3

后端比较麻烦,需要在 Controller中 注入一个实体,实体里包含List a,类似于方案三的 @RequestBody 方式,但不需要 @RequestBody 注解。

其它提交方式:

使用表单提交: 直接提交

使用jq.ajax提交: 需要自己处理后提交

方案三

后端改为 @RequestBody 的接收参数方式,然后新建一个 DTO实体类接收参数:

1
2
3
public ServerResponse deleteCategory(@RequestBody ProductCategoryDTO categoryIdArray) {
return iProductCategoryService.deleteProductCategory(categoryIdArray);
}

这里 ProductCategoryDTO 为 DTO实体类,里面就一个私有变量 List 数组,以及 get set 方法。

这个方案前端直接用 axios 的 post 方法通过 data 传递字符串数组即可。

一般我在项目中复杂的参数接收,后端都采用这个方式接收参数,但是这里只传递一个数组,我就没有采用该方案。

其它提交方式:

使用表单提交: 直接提交,但是必须修改 content-type 为 application/json

使用jq.ajax提交: 直接提交

方案四

repeat 方式,后端修改接收参数方式为:

1
public ServerResponse deleteCategory(@RequestParam(value = "idArray", defaultValue="") List<String> categoryIdArray)

乍一看好像跟第一种方案没差,细心一看,你可以发现少了”[]”,这时候后端需要接收的数组传值方式为:

1
?a=1&a=2&a=3

前端需要修改 axios 的序列化方式为 repeat:

1
2
3
4
5
6
7
axios.defaults.paramsSerializer = function (params) {
return qs.stringify(params, { arrayFormat: 'repeat' })
}
//等同于
paramsSerializer: params => {
return qs.stringify(params, { indices: false })
}})

通过查阅 qs 的文档可以发现,有4种序列化方式可以改变数组的输出格式:

1
2
3
4
5
6
7
8
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
// 'a=b,c'

其它提交方式:

使用表单提交:无法直接使用表单提交,需要转换成jq.ajax等方式提交

使用jq.ajax提交: jq.ajax提交的时候需要设置属性: traditional:true